Skip to content

feat(cli): add ado-aw list#594

Closed
jamesadevine wants to merge 3 commits into
mainfrom
feat/cli-list
Closed

feat(cli): add ado-aw list#594
jamesadevine wants to merge 3 commits into
mainfrom
feat/cli-list

Conversation

@jamesadevine
Copy link
Copy Markdown
Collaborator

Summary

Implements PR 5 of the Phase 1 CLI overhaul. Adds ado-aw list [PATH] — renders every ADO build definition that matches a local fixture along with its queueStatus, ADO folder, and latest-run summary. Output defaults to a human-readable table; --json emits a stable JSON array suitable for scripting.

CLI surface

ado-aw list [PATH]
  --org <url-or-name>          # default: from git remote
  --project <name>             # default: from git remote
  --pat <pat>                  # else AZURE_DEVOPS_EXT_PAT, else az CLI
  --all                        # include unmatched definitions
  --json                       # machine-readable output

Renderers

Text (default):

NAME                              ID    FOLDER     STATUS      LAST RUN    SOURCE
Daily safe-output smoke: noop     123   \smoke     enabled     succeeded   tests/safe-outputs/noop.lock.yml
…

JSON (--json):

[
  {
    "name": "...",
    "id": 123,
    "folder": "\\smoke",
    "queueStatus": "enabled",
    "yamlFilename": "/tests/safe-outputs/noop.lock.yml",
    "matched": true,
    "lastRun": {
      "id": 4567,
      "result": "succeeded",
      "status": "completed",
      "finishTime": "2026-05-17T08:00:00Z",
      "url": "https://..."
    }
  }
]

Plumbing

  • Implements the get_latest_build stub in src/ado/mod.rs (PR refactor(cli): extract shared ADO REST helpers into src/ado/mod.rs #580).
  • Extends DefinitionSummary with the path field (ADO folder) that list_definitions already requests via includeAllProperties=true.
  • Decision logic split into three pure functions (build_rows, render_text, render_json) with 12 unit tests.
  • Latest-build fetches are sequential; bounded fanout is a follow-up once we have 50+ matched pipelines per project.

Verified

  • cargo build
  • cargo clippy --all-targets --all-features
  • cargo test ✅ — 12 new unit tests in list.rs, 2 integration tests in tests/list_integration.rs.

Out of scope

PRs 6–8 (run / status / secrets), PR 9 (help-text grouping), and PR 10 (doc overhaul).

Implements PR 5 of the Phase 1 CLI overhaul. Renders every ADO build
definition that matches a local fixture (under PATH) along with its
queueStatus, ADO folder, and latest-run summary. Pass `--all` to also
include definitions with no matching local fixture. Output defaults
to a human-readable table; `--json` emits a stable JSON array
suitable for scripting.

Implements the `get_latest_build` stub in `src/ado/mod.rs` that PR 1
(#580) introduced. Extends `DefinitionSummary` with a `path` field
(ADO folder) that `list_definitions` already requests via
`includeAllProperties=true`.

CLI surface:

    ado-aw list [PATH] --org --project --pat --all --json

Design:

The decision logic is split into three pure functions —
`build_rows`, `render_text`, `render_json` — covered by 12
unit tests including text/JSON snapshots, `--all` filtering, sort
order, and `LastRun::from_json` field extraction (with fallback from
`_links.web.href` to top-level `url`).

Latest-build fetches are sequential for now; a bounded fanout via
`tokio::task::JoinSet` is a straightforward improvement once we have
projects with 50+ matched pipelines, but premature for the current
scale.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Rust PR Review

Summary: Mostly well-structured — one real bug in the JSON renderer worth fixing before merge, plus a minor silently-swallowed error worth a warning.

Findings

🐛 Bugs / Logic Issues

  • src/list.rs:215-225render_json doesn't use LastRun::raw; documented contract is broken.
    The struct doc comment and the ListRow doc comment both promise that the JSON renderer passes ADO build data through verbatim:

    /// the JSON renderer passes them through verbatim
    pub raw: serde_json::Value,

    But render_json reconstructs the lastRun object from only five projected fields, silently dropping everything else (requestedFor, startTime, triggerInfo, retention tags, etc.). The raw field is stored and never read. Users relying on --json for scripting will get incomplete data with no indication that fields were dropped.

    Fix: use lr.raw directly in render_json instead of rebuilding from projections, e.g.:

    "lastRun": r.last_run.as_ref().map(|lr| &lr.raw),

    The projected text-render fields (result, status) are still needed for render_text — keep those — but the JSON path should be raw pass-through as documented.

⚠️ Suggestions

  • src/list.rs:246-250match_definitions error silently swallowed with no user feedback.

    let matched = match_definitions(&client, &ado_ctx, &auth, &detected)
        .await
        .unwrap_or_default();

    If this returns an error (transient network hiccup, auth failure, etc.) the user sees zero matched rows and no explanation. A eprintln!("warning: could not match definitions: {:#}", e) on error would align with the pattern already used in the get_latest_build loop just below.

  • src/list.rs vs src/list.rs:222yamlFilename in JSON retains its leading /, stripped in text.
    Text strips trim_start_matches('/'), JSON does not. If the PR description JSON example ("/tests/safe-outputs/noop.lock.yml") is the intended stable shape, that's fine — but it's worth a brief comment so future contributors don't "fix" the inconsistency the wrong way.

✅ What Looks Good

  • get_latest_build implementation is clean and follows the existing src/ado/mod.rs request pattern precisely.
  • build_rows as a pure, easily-testable function is the right call; 12 focused unit tests cover edge cases well (case-insensitive sort, --all flag, missing last-run).
  • Soft error handling for per-definition build fetches (warn + continue) is the right UX — a single 404 shouldn't kill the whole listing.
  • Clap wiring in main.rs is idiomatic and consistent with existing subcommands.

Generated by Rust PR Reviewer for issue #594 · ● 326.3K ·

@jamesadevine
Copy link
Copy Markdown
Collaborator Author

@copilot implement feedback and suggestions

Copilot AI and others added 2 commits May 17, 2026 13:20
Copy link
Copy Markdown
Contributor

Copilot AI commented May 17, 2026

@copilot implement feedback and suggestions

Implemented the requested feedback in commits 0377960 and 29425a8. render_json now passes lastRun through verbatim from LastRun::raw, definition-match failures now emit a warning instead of being silently swallowed, and tests were updated to verify raw JSON pass-through.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/githubnext/ado-aw/issues
    • Triggering command: /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.1h-j /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.1pACCEPT /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2khy4qc2sf9dlskvb8yl07bev.0pu83j6.rcgu.o /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2lxko5zxfe5lhp1ymhbqo0tsc.0pu83j6.rcgu.o /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2mwgr5r4jmlzoft3uicnfgufa.0pu83j6.rcgu.o f6ue5bo05yrbj1ie7unlle.01ezyzu.rcgu.o lrr94ecv0qgoqeme712sdy.01ezyzu.rcgu.o 3ivitvqdg5qj44extmv48r.01ezyzu.rcgu.o lesjb3d5mr8qdbnru3upmp.01ezyzu.rcgu.o hgmyslh6mt0zhx5el6ekx8.01ezyzu.rcgu.o 8q4p5sy4boawyok17a1iez.01ezyzu.rcgu.o mbgzwd1lngqe37vxdwf9pg.01ezyzu.rcgu.o pvvor3a6k37orw81i3qtmt.01ezyzu.rcgu.o gbwa6oymsqv4igzhjqotq8.01ezyzu.rcgu.o 7a3v0f0s101bsiaqzfttsn.01ezyzu.rcgu.o ek6m19876ukvoghs1zwfq0.01ezyzu.rcgu.o 370evblbs0kccrhsyo30wm.01ezyzu.rcgu.o 5uv513m7tspcumocb68ehf.01ezyzu.rcgu.o tlet4iuf8cho5atqx9hmho.01ezyzu.rcgu.o (http block)
    • Triggering command: /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 lib --emit=dep-info,metadata -C embed-bitcode=no -C debuginfo=2 --warn=rust_2018_idioms --warn=clippy::verbose_file_reads --warn=clippy::use_self --warn=clippy::unused_self --forbid=unsafe_code 891.�� 64-REDACTED-linux-gnu/lib/libproc_macro-9681dee257b3e508.rlib 64-REDACTED-linux-gnu/lib/librustc_literal_escaper-1ebe8258df6cf91a.rlib target/debug/ado--diagnostic-width=120 --format=json ,SC1091 ck target/debug/ado--edition=2021 (http block)
  • spsprodeus21.vssps.visualstudio.com
    • Triggering command: /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.1h-j /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.1pACCEPT /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2khy4qc2sf9dlskvb8yl07bev.0pu83j6.rcgu.o /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2lxko5zxfe5lhp1ymhbqo0tsc.0pu83j6.rcgu.o /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2mwgr5r4jmlzoft3uicnfgufa.0pu83j6.rcgu.o f6ue5bo05yrbj1ie7unlle.01ezyzu.rcgu.o lrr94ecv0qgoqeme712sdy.01ezyzu.rcgu.o 3ivitvqdg5qj44extmv48r.01ezyzu.rcgu.o lesjb3d5mr8qdbnru3upmp.01ezyzu.rcgu.o hgmyslh6mt0zhx5el6ekx8.01ezyzu.rcgu.o 8q4p5sy4boawyok17a1iez.01ezyzu.rcgu.o mbgzwd1lngqe37vxdwf9pg.01ezyzu.rcgu.o pvvor3a6k37orw81i3qtmt.01ezyzu.rcgu.o gbwa6oymsqv4igzhjqotq8.01ezyzu.rcgu.o 7a3v0f0s101bsiaqzfttsn.01ezyzu.rcgu.o ek6m19876ukvoghs1zwfq0.01ezyzu.rcgu.o 370evblbs0kccrhsyo30wm.01ezyzu.rcgu.o 5uv513m7tspcumocb68ehf.01ezyzu.rcgu.o tlet4iuf8cho5atqx9hmho.01ezyzu.rcgu.o (dns block)
    • Triggering command: /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 lib --emit=dep-info,metadata -C embed-bitcode=no -C debuginfo=2 --warn=rust_2018_idioms --warn=clippy::verbose_file_reads --warn=clippy::use_self --warn=clippy::unused_self --forbid=unsafe_code 891.�� 64-REDACTED-linux-gnu/lib/libproc_macro-9681dee257b3e508.rlib 64-REDACTED-linux-gnu/lib/librustc_literal_escaper-1ebe8258df6cf91a.rlib target/debug/ado--diagnostic-width=120 --format=json ,SC1091 ck target/debug/ado--edition=2021 (dns block)
  • spsprodweu4.vssps.visualstudio.com
    • Triggering command: /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.1h-j /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.1pACCEPT /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2khy4qc2sf9dlskvb8yl07bev.0pu83j6.rcgu.o /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2lxko5zxfe5lhp1ymhbqo0tsc.0pu83j6.rcgu.o /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/init_tests-fe8c41cc83486af2.2mwgr5r4jmlzoft3uicnfgufa.0pu83j6.rcgu.o f6ue5bo05yrbj1ie7unlle.01ezyzu.rcgu.o lrr94ecv0qgoqeme712sdy.01ezyzu.rcgu.o 3ivitvqdg5qj44extmv48r.01ezyzu.rcgu.o lesjb3d5mr8qdbnru3upmp.01ezyzu.rcgu.o hgmyslh6mt0zhx5el6ekx8.01ezyzu.rcgu.o 8q4p5sy4boawyok17a1iez.01ezyzu.rcgu.o mbgzwd1lngqe37vxdwf9pg.01ezyzu.rcgu.o pvvor3a6k37orw81i3qtmt.01ezyzu.rcgu.o gbwa6oymsqv4igzhjqotq8.01ezyzu.rcgu.o 7a3v0f0s101bsiaqzfttsn.01ezyzu.rcgu.o ek6m19876ukvoghs1zwfq0.01ezyzu.rcgu.o 370evblbs0kccrhsyo30wm.01ezyzu.rcgu.o 5uv513m7tspcumocb68ehf.01ezyzu.rcgu.o tlet4iuf8cho5atqx9hmho.01ezyzu.rcgu.o (dns block)
    • Triggering command: /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 /home/REDACTED/work/ado-aw/ado-aw/target/debug/deps/ado_aw-5cd66b4699336750 lib --emit=dep-info,metadata -C embed-bitcode=no -C debuginfo=2 --warn=rust_2018_idioms --warn=clippy::verbose_file_reads --warn=clippy::use_self --warn=clippy::unused_self --forbid=unsafe_code 891.�� 64-REDACTED-linux-gnu/lib/libproc_macro-9681dee257b3e508.rlib 64-REDACTED-linux-gnu/lib/librustc_literal_escaper-1ebe8258df6cf91a.rlib target/debug/ado--diagnostic-width=120 --format=json ,SC1091 ck target/debug/ado--edition=2021 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@jamesadevine
Copy link
Copy Markdown
Collaborator Author

Superseded by #602 ( eat/cli-lifecycle-family), which consolidates all six in-flight Phase 1 lifecycle PRs into a single linear-history branch. Closing this PR; review feedback should land on #602.

jamesadevine added a commit that referenced this pull request May 17, 2026
…emove/list/status/run/secrets) (#602)

* feat(cli): add ado-aw disable

Squash-merge of #591 (feat/cli-disable). See original PR for review history and detailed rationale.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(cli): add ado-aw remove

Squash-merge of #592 (feat/cli-remove).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(cli): add ado-aw list

Squash-merge of #594 (feat/cli-list).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(cli): add ado-aw status

Implements PR 7 of the Phase 1 CLI overhaul. Renders per-pipeline
status — name, id, folder, queueStatus, latest-run summary, and a
deep link — one block per matched ADO definition. Read-only.

`status` is intentionally a thin renderer over the same data path as
`list` (same `list_definitions` + `match_definitions` +
`get_latest_build` sequence). The `--json` shape is byte-for-byte
identical to `list --json` so scripts can use either.

CLI surface:

    ado-aw status [PATH] --org --project --pat --json

The block renderer is a pure function (`render_blocks`) tested
against six scenarios:

- empty → placeholder line
- succeeded run with url → all fields rendered
- run with no url → synthesizes
  `{org_url}/{project}/_build/results?buildId={id}`
- no last run → "never" + no url line
- in-progress run (no `result` yet) → shows `status` value instead
- missing queueStatus → renders `?` placeholder

Depends on PR 5 (#594) for `crate::list::{ListRow, LastRun,
build_rows, render_json}`; reuses the `get_latest_build` ado/mod.rs
helper landed there.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): avoid duplicate ADO definition fetch in list and status

Agent-Logs-Url: https://github.com/githubnext/ado-aw/sessions/c7c2866a-891d-48c3-8336-774bba086817

Co-authored-by: jamesadevine <4742697+jamesadevine@users.noreply.github.com>

* feat(cli): add ado-aw run

Squash-merge of #595 (feat/cli-run).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(cli): rename configure to secrets with subcommands

Squash-merge of #600 (feat/cli-secrets).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): percent-encode ctx.project in all ADO URL formatters

Code-review finding on PR #602: seven URL formatters in
`src/ado/mod.rs` interpolated `ctx.project` directly into the path
segment of the request URL while five sibling functions correctly
ran the value through `percent_encoding::utf8_percent_encode(...,
PATH_SEGMENT)`. Project names containing reserved characters
(spaces, `/`, `?`, `#`, `:` etc.) would have broken the URL or
silently produced surprising responses.

Affected functions, all now using the same encoder as
`get_repository_id`, `get_definition_full`, `patch_queue_status`,
`delete_definition`, and `create_definition`:

- `list_definitions`
- `get_definition_name`
- `update_pipeline_variable` (both GET and PUT URLs)
- `queue_build`
- `get_build`
- `get_latest_build`

The `info!()` log line at the top of `match_definitions` is
unaffected (logging, not URL construction).

The existing `path_segment_*` tests already cover the encoder
behaviour; no new test is needed since these are mechanical
substitutions of an existing pattern. Full `cargo test` (1567 unit
tests + integration crates) and `cargo clippy --all-targets
--all-features` are green after the fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(run): re-check --timeout between each in-flight get_build call

Code-review follow-up on PR #602: `poll_until_complete` only checked
`started.elapsed() >= timeout` at the top of each round, so with N
in-flight builds and reqwest's 30s per-call HTTP timeout, the
operator-visible wait could overshoot `--timeout` by up to N × 30s
in the pathological all-stalled case.

Re-checks the wall-clock budget between each individual `get_build`
call inside a round. When the budget is exhausted mid-round, the
current target and every remaining one are carried forward into
`pending` so the caller's `in_progress` count stays accurate (the
loop owes a status for everything it queued).

In the common case where the poll interval is several times the HTTP
timeout, the previous behaviour was indistinguishable from the new
one — the bug only matters when poll interval ≪ HTTP timeout, which
is an awkward but plausible configuration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): percent-encode project in secrets/run; make --value-stdin conflict explicit

Three follow-ups on PR #602:

1. `src/secrets.rs::put_definition` was the last URL formatter using
   `ctx.project` unencoded. Now uses `PATH_SEGMENT` like every other
   builder in `src/ado/mod.rs`. `PATH_SEGMENT` was promoted from
   private `const` to `pub const` to support cross-module reuse.

2. `src/run.rs` was printing a deep-link to the queued build using
   unencoded `ado_ctx.project`. The URL is cosmetic (never used as an
   HTTP target), but it would render broken/unclickable for projects
   containing spaces or other URL-unsafe characters. Now encoded with
   the same `PATH_SEGMENT` encoder.

3. `ado-aw secrets set <value> --value-stdin` silently ignored
   `--value-stdin` when both were supplied (explicit positional value
   won). Added `conflicts_with = "value"` to the `value_stdin` clap
   arg so the combination is rejected at parse time with a clear
   error. Added an integration test in
   `tests/secrets_integration.rs` to pin the behaviour.

`cargo test` (1567 unit + 14 integration crates, all green) and
`cargo clippy --all-targets --all-features` pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): encode synthesized URL, surface detect errors, document parse_parameters edge

Four follow-ups on PR #602:

1. `src/status.rs::render_blocks` synthesized fallback URL was passing
   `ado_project` verbatim into the path segment when `LastRun::url`
   was absent. Now uses `PATH_SEGMENT` like every other URL builder
   in the PR. URL is text-output only, but renders broken links for
   projects with spaces or reserved chars.

2. `src/list.rs` and `src/status.rs` were swallowing
   `detect_pipelines` errors via `.unwrap_or_default()`, making
   "detection failed" indistinguishable from "no pipelines compiled
   here" — both produce zero matches downstream. Both commands are
   read-only and useful even with partial inputs (`list --all`
   doesn't need fixtures at all), so we don't bail; we emit a
   `warning: failed to scan local pipelines: …` to stderr so the
   operator can distinguish the two cases.

3. `src/run.rs::parse_parameters` silently rejects values containing
   commas (the `,` split happens before the `=` split, so the
   trailing fragment falls into the "no `=`" rejection path). The
   behaviour is intentional — commas are the documented pair
   separator — but it was undocumented. Added a doc comment
   spelling out the constraint and the one-pair-per-flag
   workaround, plus a new
   `parse_parameters_values_with_commas_split_pre_equals` unit test
   that pins both the rejection and the workaround. The doc comment
   tells future contributors to update the test if comma escaping
   is ever added.

4. `src/secrets.rs::run_set_github_token` carries an undocumented
   invariant: the deprecation warning must be emitted before any
   fallible I/O, because the integration test
   `configure_invocation_still_works_and_warns` exercises it by
   driving the function with a path that triggers an early
   canonicalize failure. Added an `IMPORTANT — invariant for the
   integration test` doc comment so a later refactor that defers
   the `eprintln!` (e.g. lazy auth init) will spot the constraint.

`cargo test` (1568 unit + 14 integration crates, all green) and
`cargo clippy --all-targets --all-features` pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): correct parse_parameters doc; cap consecutive poll errors; warn on empty status

Three follow-ups on PR #602:

1. `parse_parameters` doc-comment bug: the first bullet was tagged
   ✅ but described the same broken case as the third (✅
   `--parameters 'urls=a,b' --parameters mode=fast` still splits on
   the comma inside `urls=a,b` and fails on the trailing `b`
   fragment). Rewrote the bullet list so all broken examples are ❌
   and only the genuine "one pair per flag, no commas in values"
   workaround is ✅. Also clarified that there is currently no way
   to escape a comma inside a single `--parameters` argument, and
   pointed at the existing
   `parse_parameters_values_with_commas_split_pre_equals` unit
   test as the behaviour anchor.

2. `poll_until_complete` couldn't distinguish a permanent error
   (deleted build, revoked PAT, 404) from a transient one — both
   pushed the target back onto `next_pending` and silently retried
   until `--timeout`. Added a per-build `consecutive_errors:
   HashMap<u64, usize>` counter that resets on any successful poll
   and bails out of that specific build after
   `MAX_CONSECUTIVE_POLL_ERRORS = 3` consecutive failures, counting
   it as failed. Transient blips still retry; persistent failures
   surface within `3 × poll_interval` (default 30s) instead of
   waiting out the full `--timeout` (default 1800s).

3. `status` was silently rendering `(no matched definitions)` when
   the fixture matcher returned zero hits, which is
   indistinguishable from running in the wrong directory. Added an
   `eprintln!` warning that mirrors the existing
   `failed to scan local pipelines: …` message. The command stays
   non-fatal (read-only) by design, unlike `disable` which bails.

`cargo test` (1568 unit + 14 integration crates, all green) and
`cargo clippy --all-targets --all-features` pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): no silent allowOverride downgrade; surface comma hint; harden dry-run

Four follow-ups on PR #602:

1. **`apply_variable_set`: silent `allowOverride` downgrade on
   secret rotation.** Previously, running `secrets set TOKEN <new>`
   without `--allow-override` would re-emit the variable with
   `allowOverride: false`, silently downgrading any variable that
   was previously created (manually or by another tool) with
   `allowOverride: true`. The legacy `configure` code in
   src/configure.rs had explicit preservation logic; the
   consolidated `apply_variable_set` had lost it.

   Changed the signature from `allow_override: bool` to
   `allow_override: Option<bool>`:
   - `Some(true)` / `Some(false)` — force the flag (CLI
     `--allow-override` passes `Some(true)`).
   - `None` — **preserve** existing variable's `allowOverride`
     when overwriting; default to `false` when creating.

   `run_set` translates the CLI flag: `--allow-override` → `Some(true)`;
   absence → `None`. The deprecation alias (`run_set_github_token`)
   stays at `allow_override: false` on the CLI side, which now maps
   to `None` (preserve) — restoring parity with the pre-consolidation
   `configure` body. Help text in `src/main.rs` and `docs/cli.md`
   updated. Five new unit tests pin the matrix:
   - `Some(true)` / `Some(false)` / `None` × create/overwrite
   - Specifically asserts `None` preserves `allowOverride: true`
     (the silent-downgrade regression guard).

2. **`run.rs::print_queue_plan` silent serialize-failure.**
   `serde_json::to_string_pretty(&body).unwrap_or_default()` would
   have printed blank output if serialization ever failed. The
   value is provably JSON-safe, but defensive code should surface
   regressions instead of silently swallowing them. Switched to
   `unwrap_or_else(|e| format!("<serialization error: {e}>"))`.

3. **`run.rs::parse_parameters` opaque comma-in-value error.**
   When a user writes `--parameters urls=https://a,b`, the error
   was `Invalid --parameters pair 'b': expected key=value (no '='
   found).` — technically accurate but doesn't hint at the comma
   constraint documented above the function. Added a
   raw-argument-contains-comma detection branch that produces a
   self-diagnosable hint: `... Hint: values must not contain
   commas. The raw argument '...' was split on ',' before the
   '=' split; use a separate --parameters flag per pair.`

4. **`run.rs::dispatch` deliberate partial-queue + `--wait`
   behaviour.** When `--wait` is set and some builds fail to
   queue, the code polls the successfully-queued ones rather than
   bailing early; `queue_failure` is folded into the final exit
   code. This is intentional and the only sensible UX, but lacked
   a comment. Added a multi-paragraph block explaining all three
   cases (partial queue, zero queued, all queued) and why
   `poll_until_complete` is called with the partial slice.

Not addressed (acknowledged follow-ups, tracked elsewhere):
- Sequential `get_latest_build` fanout in `list`/`status`. Already
  documented inline; tracked as a future improvement.

`cargo test` (1572 unit + 14 integration crates, all green) and
`cargo clippy --all-targets --all-features` pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(cli): remove bails when no fixtures found; surface --parameters comma constraint in --help

Two follow-ups on PR #602:

1. **`remove` silently exited Ok(()) when no fixtures were
   detected.** For a destructive command this is the wrong UX —
   running `ado-aw remove` in the wrong directory currently
   printed "No agentic pipelines found." and exited success,
   giving no signal that nothing happened. Now mirrors `disable`:
   bails with a non-zero exit and tells the operator which path
   was scanned plus the recovery hint:

       No local agentic pipeline fixtures were found under <path>.
       Run `ado-aw compile` first (or point `ado-aw remove` at the
       repo root). `remove` refuses to exit success in this state
       because it's destructive.

2. **`--parameters` comma constraint was documented in the module
   doc-comment but not in `--help` text.** A user who writes
   `--parameters redirect_uri=https://a,b` would only learn about
   the constraint by reading the source. Added an inline
   `VALUES MUST NOT CONTAIN COMMAS …` blurb to the clap `help`
   attribute and updated `docs/cli.md` to match. The integration
   test now asserts the constraint appears in `--help` so a
   refactor that drops the warning will be caught at CI.

`cargo test` (1572 unit + 14 integration crates, all green) and
`cargo clippy --all-targets --all-features` pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants